package com.hmdp.service.impl;

import cn.hutool.core.lang.UUID;
import com.hmdp.service.ILock;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;

import java.util.Collections;
import java.util.concurrent.TimeUnit;

public class MyILockImpl implements ILock {
    private String lockName="ilock";
    private final String LOG="ILOCK";
    //单位秒
    private long duration=7;
    private StringRedisTemplate stringRedisTemplate=new StringRedisTemplate();
    //以下两个变量用于标识是谁的锁
    private final String uuid = UUID.fastUUID().toString(true);
    private long tid = Thread.currentThread().getId();
    //unlock脚本用于保证释放锁的原子性
    private static final DefaultRedisScript<Long> UNLOCK_SCRIPT;
    static {
        UNLOCK_SCRIPT=new DefaultRedisScript();
        UNLOCK_SCRIPT.setLocation(new ClassPathResource("unlockScript.lua"));
        UNLOCK_SCRIPT.setResultType(Long.TYPE);
    }
    public MyILockImpl() {
    }

    public MyILockImpl(String LOCK_NAME, StringRedisTemplate stringRedisTemplate,long duration) {
        this.lockName = lockName;
        this.stringRedisTemplate = stringRedisTemplate;
        this.duration=duration;
    }

    @Override
    public boolean lock() {
        //value为uuid+线程id 用于区分是谁的锁
        return Boolean.TRUE.equals(stringRedisTemplate.opsForValue().setIfAbsent(LOG+lockName,uuid+tid,duration, TimeUnit.SECONDS)) ;
    }

    @Override
    public void unlock() {
        //用这种代码不能保证代码的原子性 还是有可能发送删除别人的锁引发线程安全问题(在if判断完代码阻塞)
       /* if((uuid+tid).equals(stringRedisTemplate.opsForValue().get(LOG+lockName)))
         stringRedisTemplate.delete(LOG+lockName);*/
        //基于lua脚本实现上面代码的原子性
        stringRedisTemplate.execute(UNLOCK_SCRIPT, Collections.singletonList(LOG+lockName),uuid+tid);
    }
}
